JS - Objecten - Prototype
apply
() en call
(), en eigenschappen als length
en constructor
, hebben functies ook een eigenschap met de naam prototype
.Beschrijving
Je hebt misschien al horen zeggen dat in JavaScript, alles een object is. Als je niet weet hoe een object eruit ziet in JavaScript vindt je voorbeelden op JS - Objecten - Beschrijving.
Hoewel dit niet altijd waar is, wordt de bovenstaande bewering toch als waar aanvaard, omdat JavaScript een prototype-gebaseerde object georiënteerde programmeertaal is, en niet op klassen is gebaseerd.
In JavaScript zijn er twee waardetypen:
- Primitieven: Strings, Numbers, Booleans, Undefined en Null
- Objecten: arrays, functies en datums
Alhoewel niet alles in JavaScript een object is, worden de niet-objectdingen tijdens het compileren in een object verpakt, waardoor JavaScript echt ingewikkelde bewerkingen kan uitvoeren. Zelfs als je denkt dat een waarde in je code geen object is, is de kans groot dat JavaScript deze als een object heeft verpakt.
Als we bijvoorbeeld een lege functie maken met de naam plopperdeplop
:
function plopperdeplop() {}
Je kan zelf zien dat functies in JavaScript ook objecten zijn. Als we een eigenschap met de naam type
toevoegen en de waarde in de terminal uitprinten zie je dat de plopperplop
functie nu ook een object is:
function plopperdeplop() {}; plopperdeplop.type = 'Kabouter Plop'; console.log(plopperdeplop); // output plopperdeplop() arguments: null caller: null length: 0 name: "plopperdeplop" prototype: Object { … } type: "Kabouter Plop" <prototype>: function ()
Vanaf je een functie hebt gedefinieerd kan je de eigenschappen van het prototype Object
ervan benaderen:
function som(a, b, c) { return a + b + c; } som.length; 3 som.constructor; function Function() { [native code] }
Ook de prototype eigenschap is vanaf dat je de functie hebt gedefinieerd, ter beschikking. De oorspronkelijke waarde van de prototype eigenschap is een "leeg" object. Alleen de voor gedefinieerde functies en de eigenschap __proto__
zitten erin:
som.prototype; { [functions]: , __proto__: { } }
Je kan nu zelf eigenschappen en methoden toevoegen. Die zullen geen effect hebben op de som()
functie zelf, ze worden enkel gebruikt als je functie als een constructor gebruikt.
Eigenschappen en methoden toevoegen
We hebben al geleerd hoe je constructor functies definieert die je kan gebruiken om nieuwe objecten te maken (construeren). Het belangrijkste idee hierachter is dat je binnen een functie die je aanroept met new
, je toegang hebt tot de this
waarde. De waarde this
verwijst naar het object dat door de constructor zal worden geretourneerd. Met de waarde this
kan je methoden en eigenschappen aan aan het object toevoegen om die manier de functionaliteit van het object te vermeerderen.
We nemen opnieuw als voorbeeld onze Persoon
constructor functie met twee eigenschappen en één methode:
function Persoon(voornaam, familienaam) { this.voornaam = voornaam; this.familienaam = familienaam; this.wieBenIk = function () { return 'Ik ben ' + this.voornaam + ' ' + this.familienaam + '.'; }; } var persoon = new Persoon('Henri', 'Bergson'); persoon.wieBenIk(); "Ik ben Henri Bergson."
En wat zit er nu in de eigenschap prototype?
persoon.prototype; undefined
Niet veel dus. We kunnen nadat we de functie Persoon gedefinieerd hebben achteraf nog eigenschappen en methoden toevoegen met behulp van de prototype eigenschap. Dus de eigenschap prototype biedt nog een extra manier om functionaliteit aan het object toe te voegen.
function Persoon(voornaam, familienaam) { this.voornaam = voornaam; this.familienaam = familienaam; this.wieBenIk = function () { return 'Ik ben ' + this.voornaam + ' ' + this.familienaam + '.'; }; } var persoon = new Persoon('Henri', 'Bergson');
Met de eigenschap prototype kunnen we een array met titels van boeken aan het object toevoegen:
Persoon.prototype.boeken = ["Essai sur les données immédiates de la conscience", "Matière et Mémoire", "Le rire", "Introduction à la métaphysique", "L'Évolution créatrice", "La Perception du changement", "Durée et simultanéité. À propos de la théorie d'Einstein", "Les deux sources de la morale et de la religion", "La pensée et le mouvant"];
Evenals een methode die een string retourneert met de boeken die de persoon geschreven heeft. Daarvoor plakken we alle titels in de boeken array aan elkaar gescheiden door een 'en' en plaatsen we de titels tussen dubbele aanhalingstekens. Let erop dat we de eigenschap prototype van de functie nemen en niet van de instantie:
Persoon.prototype.welkeBoekenHebIkGeschreven = function () { return this.voornaam + ' ' + this.familienaam + ' is de schrijver van "' + this.boeken.join('" en van "') + '".'; } }
Als we deze functie uitvoeren krijgen we:
persoon.welkeBoekenHebIkGeschreven();
"Henri Bergson is de schrijver van "Essai sur les données immédiates de la conscience" en van "Matière et Mémoire" en van "Le rire" en van "Introduction à la métaphysique" en van "L'Évolution créatrice" en van "La Perception du changement" en van "Durée et simultanéité. À propos de la théorie d'Einstein" en van "Les deux sources de la morale et de la religion" en van "La pensée et le mouvant"."
En nu komt het! We maken een tweede instantie van het object Persoon aan voor een andere schrijver en we roepen de functie welkeBoekenHebIkGeschreven() op krijgen we dezelfde lijst als voor Henri Bergson:
var persoon2 = new Persoon('Paul', 'Van Ostayen'); persoon2.welkeBoekenHebIkGeschreven();
"Henri Bergson is de schrijver van "Essai sur les données immédiates de la conscience" en van "Matière et Mémoire" en van "Le rire" en van "Introduction à la métaphysique" en van "L'Évolution créatrice" en van "La Perception du changement" en van "Durée et simultanéité. À propos de la théorie d'Einstein" en van "Les deux sources de la morale et de la religion" en van "La pensée et le mouvant"."
Hoe komt dat? We hebben de boeken eigenschap toegekend aan het prototype van de functie. Dat wil zeggen dat elk objecten die met de new operator op basis van de functie Persoon gemaakt worden dezelfde lijst zullen delen. De boekenlijst behoort tot de functie en dus tot alle instanties ervan.
Het is dus beter om in de prototype eigenschap alleen de eigenschap boeken te declareren en in te stellen op een lege array:
Persoon.prototype.boeken = [];
De specifieke boekenlijst voegen we dan toe aan de respectievelijke instanties. We kennen de boekenlijst aan de persoon Henri Bergson toe en alleen aan hem:
persoon.boeken = ["Essai sur les données immédiates de la conscience", "Matière et Mémoire", "Le rire", "Introduction à la métaphysique", "L'Évolution créatrice", "La Perception du changement", "Durée et simultanéité. À propos de la théorie d'Einstein", "Les deux sources de la morale et de la religion", "La pensée et le mouvant"];
We passen de methode welkeBoekenHebIkGeschreven aan en kijken eerst of er boeken in de lijst staan, immers als er geen boeken in staan moeten we dat melden:
Persoon.prototype.welkeBoekenHebIkGeschreven = function () { if (this.boeken.length == 0) { return this.voornaam + ' ' + this.familienaam + ' heeft geen boeken geschreven.'; } else { return this.voornaam + ' ' + this.familienaam + ' is de schrijver van "' + this.boeken.join('" en van "') + '".'; } }
We gaan nu na of de boekenlijst van Henri Bergson alleen in zijn object zit en niet in dat van Paul Ostayen:
persoon2.welkeBoekenHebIkGeschreven(); "Paul Van Ostayen heeft geen boeken geschreven."
En de lijst van de boeken van Henri Berson wordt wel geretourneerd:
persoon.welkeBoekenHebIkGeschreven();
"Henri Bergson is de schrijver van "Essai sur les données immédiates de la conscience" en van "Matière et Mémoire" en van "Le rire" en van "Introduction à la métaphysique" en van "L'Évolution créatrice" en van "La Perception du changement" en van "Durée et simultanéité. À propos de la théorie d'Einstein" en van "Les deux sources de la morale et de la religion" en van "La pensée et le mouvant"."
Bronnen
Rajat S, Understanding JavaScript’s Prototypal Inheritance, 17/9/2018